﻿// -----------------------------------------------------------------------
// <copyright file="PushRequestRepository.cs" company="Zen Design Corp">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Zen.BlackBerry.Push.Repositories
{
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using Zen.BlackBerry.Pap;
	using Zen.BlackBerry.Push.DataAccess;
	using Zen.BlackBerry.Push.Request;
	using Zen.Data.Extensions;

	/// <summary>
	/// TODO: Update summary.
	/// </summary>
	public class PushRequestRepository : Repository, IPushRequestRepository
	{
		public PushRequestRepository()
		{
		}

		private void DeleteRequestsCore(IQueryable<DbPushRequest> query, bool completed, string deletedBy = null)
		{
			if (completed)
			{
				query = query.Where((item) =>
					!item.RequestDetails.Any((detail) =>
						detail.MessageState != (short)MessageState.Pending &&
						detail.MessageState != (short)MessageState.Unknown));
			}

			foreach (var dbRequest in query.ToArray())
			{
				ObjectContext.DbPushRequests.DeleteObject(dbRequest);
			}
			ObjectContext.SaveChanges();
		}

		#region IPushRequestRepository Members

		public void AddPushRequest(PushRequest pushRequest)
		{
			DbPushApplication dbApplication = ObjectContext.DbPushApplications
				.First((item) => item.RimApplicationId == pushRequest.PushApplicationId);

			DateTime utcNow = DateTime.UtcNow;
			DbPushRequest dbRequest =
				new DbPushRequest
				{
					PushRequestId = Guid.NewGuid(),
					Application = dbApplication,
					AddressCount = pushRequest.AddressCount,
					ContentLength = pushRequest.ContentLength,
					CreatedDate = utcNow,
					DeliveryMethod = (short)pushRequest.DeliveryMethod,
					EnterpriseNotifyUrl = pushRequest.EnterpriseNotifyUrl,
					LastUpdatedDate = utcNow,
					PublicNotifyUrl = pushRequest.PublicNotifyUrl,
					PushId = pushRequest.Id,
					TotalContentLength = pushRequest.TotalContentLength
				};
			ObjectContext.DbPushRequests.AddObject(dbRequest);
			ObjectContext.SaveChanges();
		}

		public void DeletePushRequest(string pushId)
		{
			IQueryable<DbPushRequest> query = ObjectContext.DbPushRequests
				.Where((item) => item.PushId == pushId);
			DeleteRequestsCore(query, false);
		}

		public void DeletePushRequests(bool completed, string deletedBy)
		{
			IQueryable<DbPushRequest> query = ObjectContext.DbPushRequests
				.Include("RequestDetails");
			DeleteRequestsCore(query, completed, deletedBy);
		}

		public void DeletePushRequests(IEnumerable<string> pushIds)
		{
			IQueryable<DbPushRequest> query = ObjectContext.DbPushRequests
				.ContainsEx((item) => item.PushId, pushIds);
			DeleteRequestsCore(query, false);
		}

		public void DeletePushRequestsByDate(DateTime toDate, bool completed, string deletedBy)
		{
			IQueryable<DbPushRequest> query = ObjectContext.DbPushRequests
				.Include("RequestDetails")
				.Where((item) => item.CreatedDate < toDate);
			DeleteRequestsCore(query, completed, deletedBy);
		}

		public void DeletePushRequestsByPushAppId(string pushApplicationId, bool completed, string deletedBy)
		{
			IQueryable<DbPushRequest> query = ObjectContext.DbPushRequests
				.Include("RequestDetails")
				.Where((item) => item.Application.RimApplicationId == pushApplicationId);
			DeleteRequestsCore(query, completed, deletedBy);
		}

		public void DeletePushRequestsByPushAppIdAndDate(string pushApplicationId, DateTime toDate, bool completed, string deletedBy)
		{
			IQueryable<DbPushRequest> query = ObjectContext.DbPushRequests
				.Include("RequestDetails")
				.Where((item) => item.Application.RimApplicationId == pushApplicationId && item.CreatedDate < toDate);
			DeleteRequestsCore(query, completed, deletedBy);
		}

		public IEnumerable<PushRequest> FindAll()
		{
			return ObjectContext.DbPushRequests
				.Include("Application")
				.Select((item) =>
					new PushRequest
					{
						AddressCount = item.AddressCount,
						ContentLength = item.ContentLength,
						CreatedDate = item.CreatedDate,
						DeliveryMethod = (DeliveryMethod)item.DeliveryMethod,
						EnterpriseNotifyUrl = item.EnterpriseNotifyUrl,
						ExpiryDate = item.ExpiryDate,
						Id = item.PushId,
						LastUpdatedDate = item.LastUpdatedDate,
						PublicNotifyUrl = item.PublicNotifyUrl,
						PushApplicationId = item.Application.RimApplicationId,
						TotalContentLength = item.TotalContentLength
					});
		}

		public IEnumerable<PushRequest> FindByAppId(string id)
		{
			return ObjectContext.DbPushRequests
				.Include("Application")
				.Where((item) => item.Application.RimApplicationId == id)
				.Select((item) =>
					new PushRequest
					{
						AddressCount = item.AddressCount,
						ContentLength = item.ContentLength,
						CreatedDate = item.CreatedDate,
						DeliveryMethod = (DeliveryMethod)item.DeliveryMethod,
						EnterpriseNotifyUrl = item.EnterpriseNotifyUrl,
						ExpiryDate = item.ExpiryDate,
						Id = item.PushId,
						LastUpdatedDate = item.LastUpdatedDate,
						PublicNotifyUrl = item.PublicNotifyUrl,
						PushApplicationId = item.Application.RimApplicationId,
						TotalContentLength = item.TotalContentLength
					});
		}

		public IEnumerable<PushRequest> FindByDateRange(DateTime fromDate, DateTime toDate, int startIndex, int endIndex)
		{
			return ObjectContext.DbPushRequests
				.Include("Application")
				.Where((item) => item.CreatedDate >= fromDate && item.CreatedDate <= toDate)
				.Skip(startIndex)
				.Take(endIndex - startIndex + 1)
				.Select((item) =>
					new PushRequest
					{
						AddressCount = item.AddressCount,
						ContentLength = item.ContentLength,
						CreatedDate = item.CreatedDate,
						DeliveryMethod = (DeliveryMethod)item.DeliveryMethod,
						EnterpriseNotifyUrl = item.EnterpriseNotifyUrl,
						ExpiryDate = item.ExpiryDate,
						Id = item.PushId,
						LastUpdatedDate = item.LastUpdatedDate,
						PublicNotifyUrl = item.PublicNotifyUrl,
						PushApplicationId = item.Application.RimApplicationId,
						TotalContentLength = item.TotalContentLength
					});
		}

		public PushRequest FindById(string id)
		{
			return ObjectContext.DbPushRequests
				.Include("Application")
				.Where((item) => item.PushId == id)
				.Select((item) =>
					new PushRequest
					{
						AddressCount = item.AddressCount,
						ContentLength = item.ContentLength,
						CreatedDate = item.CreatedDate,
						DeliveryMethod = (DeliveryMethod)item.DeliveryMethod,
						EnterpriseNotifyUrl = item.EnterpriseNotifyUrl,
						ExpiryDate = item.ExpiryDate,
						Id = item.PushId,
						LastUpdatedDate = item.LastUpdatedDate,
						PublicNotifyUrl = item.PublicNotifyUrl,
						PushApplicationId = item.Application.RimApplicationId,
						TotalContentLength = item.TotalContentLength
					})
				.FirstOrDefault();
		}

		public IEnumerable<PushRequest> FindIncomplete(string applicationId)
		{
			return ObjectContext.DbPushRequests
				.Include("Application")
				.Include("RequestDetails")
				.Where((item) =>
					item.RequestDetails.Any((detail) =>
						detail.MessageState == (short)MessageState.Unknown ||
						detail.MessageState == (short)MessageState.Pending))
				.Select((item) =>
					new PushRequest
					{
						AddressCount = item.AddressCount,
						ContentLength = item.ContentLength,
						CreatedDate = item.CreatedDate,
						DeliveryMethod = (DeliveryMethod)item.DeliveryMethod,
						EnterpriseNotifyUrl = item.EnterpriseNotifyUrl,
						ExpiryDate = item.ExpiryDate,
						Id = item.PushId,
						LastUpdatedDate = item.LastUpdatedDate,
						PublicNotifyUrl = item.PublicNotifyUrl,
						PushApplicationId = item.Application.RimApplicationId,
						TotalContentLength = item.TotalContentLength
					});
		}

		public int GetSizeByDateRange(DateTime fromDate, DateTime toDate)
		{
			return ObjectContext.DbPushRequests
				.Count((item) => item.CreatedDate >= fromDate && item.CreatedDate <= toDate);
		}

		#endregion
	}
}
